"""
The environment middleware supplies environment constants to the request context,
based on the output of the specified environment module.  Environment values will
be put into the context of the response, and be made available within a view.

Environment Access in Views
---------------------------
Environment is accessible from the 'env' threadlocal within a view.  To use it:

from epijam.middleware.environment import env
member = env.member # environment variables accessible as attributes of 'env'.

Provider modules
----------------
Provider modules should use the following interface:

def get_env(request)

They should return a dictionary objects that returns the environment values.

"""
import logging
log = logging.getLogger('environment')

import inspect
import threading

# ================================
# = Dynamic Backends for Modules =
# ================================
def load_backend(setting_name,default_name=None):
    """
    Dynamically loads a backend module from the specified django settings
    name, or falling back to the default value if the settings is empty
    or unspecified in the settings.
    """
    backend_name = None
    from django.conf import settings as django_settings
    if hasattr(django_settings,setting_name):
        backend_name = getattr(django_settings,setting_name) or default_name
    else:
        backend_name = default_name
    
    if backend_name:
        return __import__(backend_name,'','',[''])
    else:
        raise ImportError, 'No backend module specified for %s in Django settings, and no default available.' % setting_name

env_provider = load_backend('ENVIRONMENT','environment.standard')

class EnvironmentMiddleware(object):
    """
    Middleware hook for environment system.
    """
    def process_request(self,request):
        """
        Processes incoming request.
        """
        provided_env = env_provider.get_env(request)
        env.__dict__.update(provided_env)
        return None
    
    def process_view(self,request,view_func,view_args,view_kwargs):
        """
        Processes a specific view function.
        """
        return None
    
    def process_response(self,request,response):
        """
        Processes a response from a view.
        """
        env.__dict__.clear()
        return response
    
    def process_exception(self,request,exception):
        """
        Processes an exception that occured in a view.
        """
        env.__dict__.clear()
        return None

# ===============================
# = The threadlocal environment =
# ===============================
env = threading.local() # available for the entire request lifecycle

# =============
# = Utilities =
# =============

def ctx(**kwargs):
    """
    Constructs a context for response purposes.  The context will have
    the environment in it under the 'env' namespace.
    """
    kwargs['env'] = env
    return kwargs

def lctx(**kwargs):
    """
    Constructs a context from the environment, the calling function's local
    variables, and any additional variables passed as arguments.
    """
    kwargs['env'] = env
    kwargs.update(inspect.currentframe(1).f_locals)
    return kwargs

def push_local():
    """
    Pushes the local variable onto the environment.
    """
    env.__dict__.update(inspect.currentframe(1).f_locals)

def push(**kwargs):
    """
    Pushes the specified keyword args onto the environment.
    """
    env.__dict__.update(kwargs)